﻿using System;
using System.Linq;
using System.Text;
using System.Reflection;
using System.Reflection.Emit;

namespace LeanEngine.Reflection
{
    public sealed class EmitConstructorInvoker : IConstructorInvoker
    {
        #region Declaration Members

        private Func<object> _invoker;

        #endregion

        #region PropertyInfo Members

        public ConstructorInfo ConstructorInfo { get; private set; }

        #endregion

        #region Constructor Members

        public EmitConstructorInvoker(Type classType)
        {
            this.ConstructorInfo = classType.GetConstructor(Type.EmptyTypes);

            var dynamic = new DynamicMethod(string.Empty, classType, new Type[0], this.ConstructorInfo.DeclaringType);
            var il = dynamic.GetILGenerator();

            il.DeclareLocal(this.ConstructorInfo.DeclaringType);
            il.Emit(OpCodes.Newobj, this.ConstructorInfo);
            il.Emit(OpCodes.Stloc_0);
            il.Emit(OpCodes.Ldloc_0);
            il.Emit(OpCodes.Ret);

            this._invoker = dynamic.CreateDelegate(typeof(Func<object>)) as Func<object>;
        }

        #endregion

        #region IConstructorInvoker Members

        public object Invoke(params object[] parameters)
        {
            return this._invoker();
        }

        #endregion
    }
}
